package com.atguigu.gulimall.ware.listener;

import com.atguigu.common.constant.OrderConstant;
import com.atguigu.common.constant.WareConstant;
import com.atguigu.common.to.mq.WareStockLockTo;
import com.atguigu.common.to.order.OrderTo;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.ware.config.WareRabbitMQConfig;
import com.atguigu.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.atguigu.gulimall.ware.entity.WareOrderTaskEntity;
import com.atguigu.gulimall.ware.feign.OrderFeignService;
import com.atguigu.gulimall.ware.service.WareOrderTaskDetailService;
import com.atguigu.gulimall.ware.service.WareOrderTaskService;
import com.atguigu.gulimall.ware.service.WareSkuService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

@Slf4j
@Component
public class WareRabbitMQListener {

    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    private OrderFeignService orderFeignService;

    @Autowired
    private WareSkuService wareSkuService;

    /**
     * 解锁库存
     * 1. 库存自动解锁
     *     下订单成功，扣件库存成功，后续业务失败，导致订单回滚，这时就需要回滚库存，此时数据库这种 task 与 task detail 都存在数据，可以直接查询删除
     *     下订单成功，扣件库存失败，导致订单回滚 ，此时数据库这种 task 与 task detail 都不存在数据
     *
     * @param to
     * @param message
     */
    @RabbitListener(queues = WareRabbitMQConfig.WARE_RELEASE_QUEUE_NAME)
    @Transactional
    public void handlerWareStockReleaseMessage(WareStockLockTo to, Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        String orderSn = to.getOrderSn();
        WareStockLockTo.WareStockLockDetailTo detail = to.getDetail();

        /*
         * 根据库存解锁详情信息去数据库查询是否还有此记录，
         *  如果有：
         *       远程根据订单号请求查询 订单信息
         *          存在： 判断订单状态是否为CANCELED, 是：说明需要解锁库存，否：无需解锁
         *          不存在：说明在锁定库存逻辑后，订单下单逻辑完成前发生了错误,此时订单服务已回滚，此时也需要解锁
         *  没有：说明库存锁定已经回滚，无需解锁
         */
        WareOrderTaskDetailEntity orderTaskDetail = wareOrderTaskDetailService.getBaseMapper()
                .selectOne(new QueryWrapper<WareOrderTaskDetailEntity>().eq("id", detail.getId()));
        log.info("根据库存解锁详情信息去数据库查询是否还有此记录, 订单号为 {}", orderSn);
        if (orderTaskDetail != null) {
            R r = orderFeignService.getOrderInfoByOrderSn(orderSn);
            if (r.isOk()) {
                OrderTo data = r.getData(new TypeReference<OrderTo>() {
                });
                if (data == null || Objects.equals(data.getStatus(), OrderConstant.OrderStatusEnum.CANCELED.getCode())) {
                    // 解锁库存
                    // 查询 工作单状态
                    if (orderTaskDetail.getLockStatus() == WareConstant.WareOrderTaskDetailLockStatusEnum.LOCKED.getCode()) {
                        boolean success = unlockStockBySkuIdAndWareId(detail.getSkuId(), detail.getWareId(), detail.getSkuNum(), detail.getId());
                        if (success) {
                            log.info("库存解锁成功 订单号为 {}", orderSn);
                            channel.basicAck(deliveryTag, false);
                        } else {
                            log.info("库存解锁失败 订单号为 {}", orderSn);
                            channel.basicReject(deliveryTag, true);
                        }
                    } else {
                        log.info("任务单为非锁定状态，无需解锁 订单号为 {}", orderSn);
                        channel.basicReject(deliveryTag, true);
                    }
                } else {
                    log.info("订单状态正常，无需解锁 订单号为 {}", orderSn);
                    channel.basicReject(deliveryTag, true);
                }
            } else {
                // 远程调用失败，无法进行解锁
                log.info("远程调用订单信息失败，无法进行解锁 订单号为 {}", orderSn);
                channel.basicReject(deliveryTag, true);
            }
        } else {
            // 无需解锁，直接确认消息
            log.info("说明库存锁定已经回滚，无需解锁  订单号为 {}", orderSn);
            channel.basicAck(deliveryTag, false);
        }

    }


    @RabbitListener(queues = WareRabbitMQConfig.WARE_RELEASE_QUEUE_NAME)
    @Transactional
    public void handlerWareStockReleaseMessage(OrderTo orderTo, Message message, Channel channel) throws IOException {
        try {
            List<WareOrderTaskDetailEntity> details = wareOrderTaskDetailService.getTaskDetailsByOrderSn(orderTo.getOrderSn());
            for (WareOrderTaskDetailEntity detail : details) {
                unlockStockBySkuIdAndWareId(detail.getSkuId(), detail.getWareId(), detail.getSkuNum(), detail.getId());
            }
            log.info("订单服务过期主动调用库存逻辑解锁正常完成，订单号为 {}", orderTo.getOrderSn());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.info("订单服务过期主动调用库存逻辑解锁异常失败，订单号为 {}", orderTo.getOrderSn());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            throw new RuntimeException(e);
        }


    }

    private boolean unlockStockBySkuIdAndWareId(Long skuId, Long wareId, Integer num, Long taskDetailId) {
        return wareSkuService.unlockStockBySkuIdAndWareId(skuId, wareId, num)
                && wareOrderTaskDetailService.unlockStock(taskDetailId);
    }
}
